/*
 * LDIR
 * 
 * LDIR, a GPS cartography application built for Let's Do It Romania eco 
 * campaign.
 * Copyright (C) 2010 Genera Software <office@generasoftware.com>
 * 
 * http://generasoftware.com/
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _EVENTS_H_
#define _EVENTS_H_

#include <e32base.h>

template<typename R>
class TEventHandlerInvoker0;

template<typename R>
class TEventHandler0
    {
public:
    typedef R return_type;
    typedef TEventHandlerInvoker0<R> invoker_type;

    TEventHandler0() :
        object_ptr( 0 ), stub_ptr( 0 )
        {
        }

    template<return_type(*TMethod)()>
    static TEventHandler0 * FromFunctionL()
        {
        return FromStubL( 0, &function_stub<TMethod> );
        }

    template<class T, return_type(T::*TMethod)()>
    static TEventHandler0 * FromMethodL( T* object_ptr )
        {
        return FromStubL( object_ptr, &method_stub<T, TMethod> );
        }

    template<class T, return_type(T::*TMethod)() const>
    static TEventHandler0 * FromConstMethodL( T const* object_ptr )
        {
        return FromStubL( const_cast<T*> ( object_ptr ), &const_method_stub<T,
            TMethod> );
        }

    return_type operator()() const
        {
        return ( *stub_ptr )( object_ptr );
        }

    operator bool() const
        {
        return stub_ptr != 0;
        }

    bool operator!() const
        {
        return !( operator bool() );
        }

private:

    typedef return_type (*stub_type)( void* object_ptr );

    void* object_ptr;
    stub_type stub_ptr;

    static TEventHandler0 * FromStubL( void* object_ptr, stub_type stub_ptr )
        {
        TEventHandler0 * d = new ( ELeave ) TEventHandler0;
        d->object_ptr = object_ptr;
        d->stub_ptr = stub_ptr;
        return d;
        }

    template<return_type(*TMethod)()>
    static return_type function_stub( void* )
        {
        return ( TMethod )();
        }

    template<class T, return_type(T::*TMethod)()>
    static return_type method_stub( void* object_ptr )
        {
        T* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )();
        }

    template<class T, return_type(T::*TMethod)() const>
    static return_type const_method_stub( void* object_ptr )
        {
        T const* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )();
        }
    };

template<typename R>
class TEventHandlerInvoker0
    {

public:
    TEventHandlerInvoker0()
        {
        }

    template<class TEventHandler>
    R operator()( TEventHandler d ) const
        {
        return d();
        }
    };

template<typename R>
class TEvent0
    {
    typedef R return_type;
public:
    TEvent0()
        {
        }
    ~ TEvent0()
        {
        iDelegates.ResetAndDestroy();
        }

    TEvent0<R>& operator +=( TEventHandler0<R>& aDelegate )
        {
        iDelegates.Append( &aDelegate );
        return *this;
        }

    TEvent0<R>& operator -=( TEventHandler0<R>& aDelegate )
        {
        TInt pos = iDelegates.Find( &aDelegate );
        if ( pos != KErrNotFound )
            {
            iDelegates.Remove( pos );
            }
        return *this;
        }

    return_type operator()() const
        {
        for ( TInt i = 0; i < iDelegates.Count(); ++i )
            {
            ( *iDelegates[i] )();
            }
        }
private:
    RPointerArray<TEventHandler0<R> > iDelegates;
    };

template<typename R, typename A1>
class TEventHandlerInvoker1;

template<typename R, typename A1>
class TEventHandler1
    {
public:
    typedef R return_type;
    typedef TEventHandlerInvoker1<R, A1> invoker_type;

    TEventHandler1() :
        object_ptr( 0 ), stub_ptr( 0 )
        {
        }

    template<return_type(*TMethod)( A1 )>
    static TEventHandler1 * FromFunctionL()
        {
        return FromStubL( 0, &function_stub<TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1 )>
    static TEventHandler1 * FromMethodL( T* object_ptr )
        {
        return FromStubL( object_ptr, &method_stub<T, TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1 ) const>
    static TEventHandler1 * FromConstMethodL( T const* object_ptr )
        {
        return FromStubL( const_cast<T*> ( object_ptr ), &const_method_stub<T,
            TMethod> );
        }

    return_type operator()( A1 a1 ) const
        {
        return ( *stub_ptr )( object_ptr, a1 );
        }

    operator bool() const
        {
        return stub_ptr != 0;
        }

    bool operator!() const
        {
        return !( operator bool() );
        }

private:

    typedef return_type (*stub_type)( void* object_ptr, A1 a1 );

    void* object_ptr;
    stub_type stub_ptr;

    static TEventHandler1 * FromStubL( void* object_ptr, stub_type stub_ptr )
        {
        TEventHandler1 * d = new ( ELeave ) TEventHandler1;
        d->object_ptr = object_ptr;
        d->stub_ptr = stub_ptr;
        return d;
        }

    template<return_type(*TMethod)( A1 )>
    static return_type function_stub( void*, A1 a1 )
        {
        return ( TMethod )( a1 );
        }

    template<class T, return_type(T::*TMethod)( A1 )>
    static return_type method_stub( void* object_ptr, A1 a1 )
        {
        T* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1 );
        }

    template<class T, return_type(T::*TMethod)( A1 ) const>
    static return_type const_method_stub( void* object_ptr, A1 a1 )
        {
        T const* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1 );
        }
    };

template<typename R, typename A1>
class TEventHandlerInvoker1
    {
    A1 a1;

public:
    TEventHandlerInvoker1( A1 a1 ) :
        a1( a1 )
        {
        }

    template<class TEventHandler>
    R operator()( TEventHandler d ) const
        {
        return d( a1 );
        }
    };

template<typename R, typename A1>
class TEvent1
    {
    typedef R return_type;
public:
    TEvent1()
        {

        }
    ~ TEvent1()
        {
        iDelegates.ResetAndDestroy();
        }

    TEvent1<R, A1>& operator +=( TEventHandler1<R, A1>& aDelegate )
        {
        iDelegates.Append( &aDelegate );
        return *this;
        }

    TEvent1<R, A1>& operator -=( TEventHandler1<R, A1>& aDelegate )
        {
        TInt pos = iDelegates.Find( &aDelegate );
        if ( pos != KErrNotFound )
            {
            iDelegates.Remove( pos );
            }
        return *this;
        }

    return_type operator()( A1 a1 ) const
        {
        for ( TInt i = 0; i < iDelegates.Count(); ++i )
            {
            ( *iDelegates[i] )( a1 );
            }
        }
private:
    RPointerArray<TEventHandler1<R, A1> > iDelegates;
    };

template<typename R, typename A1, typename A2>
class TEventHandlerInvoker2;

template<typename R, typename A1, typename A2>
class TEventHandler2
    {
public:
    typedef R return_type;
    typedef TEventHandlerInvoker2<R, A1, A2> invoker_type;

    TEventHandler2() :
        object_ptr( 0 ), stub_ptr( 0 )
        {
        }

    template<return_type(*TMethod)( A1, A2 )>
    static TEventHandler2 * FromFunctionL()
        {
        return FromStubL( 0, &function_stub<TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1, A2 )>
    static TEventHandler2 * FromMethodL( T* object_ptr )
        {
        return FromStubL( object_ptr, &method_stub<T, TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1, A2 ) const>
    static TEventHandler2 * FromConstMethodL( T const* object_ptr )
        {
        return FromStubL( const_cast<T*> ( object_ptr ), &const_method_stub<T,
            TMethod> );
        }

    return_type operator()( A1 a1, A2 a2 ) const
        {
        return ( *stub_ptr )( object_ptr, a1, a2 );
        }

    operator bool() const
        {
        return stub_ptr != 0;
        }

    bool operator!() const
        {
        return !( operator bool() );
        }

private:

    typedef return_type (*stub_type)( void* object_ptr, A1 a1, A2 a2 );

    void* object_ptr;
    stub_type stub_ptr;

    static TEventHandler2 * FromStubL( void* object_ptr, stub_type stub_ptr )
        {
        TEventHandler2 * d = new ( ELeave ) TEventHandler2;
        d->object_ptr = object_ptr;
        d->stub_ptr = stub_ptr;
        return d;
        }

    template<return_type(*TMethod)( A1, A2 )>
    static return_type function_stub( void*, A1 a1, A2 a2 )
        {
        return ( TMethod )( a1, a2 );
        }

    template<class T, return_type(T::*TMethod)( A1, A2 )>
    static return_type method_stub( void* object_ptr, A1 a1, A2 a2 )
        {
        T* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1, a2 );
        }

    template<class T, return_type(T::*TMethod)( A1, A2 ) const>
    static return_type const_method_stub( void* object_ptr, A1 a1, A2 a2 )
        {
        T const* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1, a2 );
        }
    };

template<typename R, typename A1, typename A2>
class TEventHandlerInvoker2
    {
    A1 a1;
    A2 a2;

public:
    TEventHandlerInvoker2( A1 a1, A2 a2 ) :
        a1( a1 ), a2( a2 )
        {
        }

    template<class TEventHandler>
    R operator()( TEventHandler d ) const
        {
        return d( a1, a2 );
        }
    };

template<typename R, typename A1, typename A2>
class TEvent2
    {
    typedef R return_type;
public:
    TEvent2()
        {

        }
    ~ TEvent2()
        {
        iDelegates.ResetAndDestroy();
        }

    TEvent2<R, A1, A2>& operator +=( TEventHandler2<R, A1, A2>& aDelegate )
        {
        iDelegates.Append( &aDelegate );
        return *this;
        }

    TEvent2<R, A1, A2>& operator -=( TEventHandler2<R, A1, A2>& aDelegate )
        {
        TInt pos = iDelegates.Find( &aDelegate );
        if ( pos != KErrNotFound )
            {
            iDelegates.Remove( pos );
            }
        return *this;
        }

    return_type operator()( A1 a1, A2 a2 ) const
        {
        for ( TInt i = 0; i < iDelegates.Count(); ++i )
            {
            ( *iDelegates[i] )( a1, a2 );
            }
        }
private:
    RPointerArray<TEventHandler2<R, A1, A2> > iDelegates;
    };

template<typename R, typename A1, typename A2, typename A3>
class TEventHandlerInvoker3;

template<typename R, typename A1, typename A2, typename A3>
class TEventHandler3
    {
public:
    typedef R return_type;
    typedef TEventHandlerInvoker3<R, A1, A2, A3> invoker_type;

    TEventHandler3() :
        object_ptr( 0 ), stub_ptr( 0 )
        {
        }

    template<return_type(*TMethod)( A1, A2, A3 )>
    static TEventHandler3 * FromFunctionL()
        {
        return FromStubL( 0, &function_stub<TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3 )>
    static TEventHandler3 * FromMethodL( T* object_ptr )
        {
        return FromStubL( object_ptr, &method_stub<T, TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3 ) const>
    static TEventHandler3 * FromConstMethodL( T const* object_ptr )
        {
        return FromStubL( const_cast<T*> ( object_ptr ), &const_method_stub<T,
            TMethod> );
        }

    return_type operator()( A1 a1, A2 a2, A3 a3 ) const
        {
        return ( *stub_ptr )( object_ptr, a1, a2, a3 );
        }

    operator bool() const
        {
        return stub_ptr != 0;
        }

    bool operator!() const
        {
        return !( operator bool() );
        }

private:

    typedef return_type (*stub_type)( void* object_ptr, A1 a1, A2 a2, A3 a3 );

    void* object_ptr;
    stub_type stub_ptr;

    static TEventHandler3 * FromStubL( void* object_ptr, stub_type stub_ptr )
        {
        TEventHandler3 * d = new ( ELeave ) TEventHandler3;
        d->object_ptr = object_ptr;
        d->stub_ptr = stub_ptr;
        return d;
        }

    template<return_type(*TMethod)( A1, A2, A3 )>
    static return_type function_stub( void*, A1 a1, A2 a2, A3 a3 )
        {
        return ( TMethod )( a1, a2, a3 );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3 )>
    static return_type method_stub( void* object_ptr, A1 a1, A2 a2, A3 a3 )
        {
        T* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1, a2, a3 );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3 ) const>
    static return_type const_method_stub( void* object_ptr, A1 a1, A2 a2, A3 a3 )
        {
        T const* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1, a2, a3 );
        }
    };

template<typename R, typename A1, typename A2, typename A3>
class TEventHandlerInvoker3
    {
    A1 a1;
    A2 a2;
    A3 a3;

public:
    TEventHandlerInvoker3( A1 a1, A2 a2, A3 a3 ) :
        a1( a1 ), a2( a2 ), a3( a3 )
        {
        }

    template<class TEventHandler>
    R operator()( TEventHandler d ) const
        {
        return d( a1, a2, a3 );
        }
    };

template<typename R, typename A1, typename A2, typename A3>
class TEvent3
    {
    typedef R return_type;
public:
    TEvent3()
        {

        }
    ~ TEvent3()
        {
        iDelegates.ResetAndDestroy();
        }

    TEvent3<R, A1, A2, A3>& operator +=(
        TEventHandler3<R, A1, A2, A3>& aDelegate )
        {
        iDelegates.Append( &aDelegate );
        return *this;
        }

    TEvent3<R, A1, A2, A3>& operator -=(
        TEventHandler3<R, A1, A2, A3>& aDelegate )
        {
        TInt pos = iDelegates.Find( &aDelegate );
        if ( pos != KErrNotFound )
            {
            iDelegates.Remove( pos );
            }
        return *this;
        }

    return_type operator()( A1 a1, A2 a2, A3 a3 ) const
        {
        for ( TInt i = 0; i < iDelegates.Count(); ++i )
            {
            ( *iDelegates[i] )( a1, a2, a3 );
            }
        }
private:
    RPointerArray<TEventHandler3<R, A1, A2, A3> > iDelegates;
    };

template<typename R, typename A1, typename A2, typename A3, typename A4>
class TEventHandlerInvoker4;

template<typename R, typename A1, typename A2, typename A3, typename A4>
class TEventHandler4
    {
public:
    typedef R return_type;
    typedef TEventHandlerInvoker4<R, A1, A2, A3, A4> invoker_type;

    TEventHandler4() :
        object_ptr( 0 ), stub_ptr( 0 )
        {
        }

    template<return_type(*TMethod)( A1, A2, A3, A4 )>
    static TEventHandler4 * FromFunctionL()
        {
        return FromStubL( 0, &function_stub<TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3, A4 )>
    static TEventHandler4 * FromMethodL( T* object_ptr )
        {
        return FromStubL( object_ptr, &method_stub<T, TMethod> );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3, A4 ) const>
    static TEventHandler4 * FromConstMethodL( T const* object_ptr )
        {
        return FromStubL( const_cast<T*> ( object_ptr ), &const_method_stub<T,
            TMethod> );
        }

    return_type operator()( A1 a1, A2 a2, A3 a3, A4 a4 ) const
        {
        return ( *stub_ptr )( object_ptr, a1, a2, a3, a4 );
        }

    operator bool() const
        {
        return stub_ptr != 0;
        }

    bool operator!() const
        {
        return !( operator bool() );
        }

private:

    typedef return_type (*stub_type)( void* object_ptr, A1 a1, A2 a2, A3 a3,
        A4 a4 );

    void* object_ptr;
    stub_type stub_ptr;

    static TEventHandler4 * FromStubL( void* object_ptr, stub_type stub_ptr )
        {
        TEventHandler4 * d = new ( ELeave ) TEventHandler4;
        d->object_ptr = object_ptr;
        d->stub_ptr = stub_ptr;
        return d;
        }

    template<return_type(*TMethod)( A1, A2, A3, A4 )>
    static return_type function_stub( void*, A1 a1, A2 a2, A3 a3, A4 a4 )
        {
        return ( TMethod )( a1, a2, a3, a4 );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3, A4 )>
    static return_type method_stub( void* object_ptr, A1 a1, A2 a2, A3 a3,
        A4 a4 )
        {
        T* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1, a2, a3, a4 );
        }

    template<class T, return_type(T::*TMethod)( A1, A2, A3, A4 ) const>
    static return_type const_method_stub( void* object_ptr, A1 a1, A2 a2,
        A3 a3, A4 a4 )
        {
        T const* p = static_cast<T*> ( object_ptr );
        return ( p->*TMethod )( a1, a2, a3, a4 );
        }
    };

template<typename R, typename A1, typename A2, typename A3, typename A4>
class TEventHandlerInvoker4
    {
    A1 a1;
    A2 a2;
    A3 a3;
    A4 a4;

public:
    TEventHandlerInvoker4( A1 a1, A2 a2, A3 a3, A4 a4 ) :
        a1( a1 ), a2( a2 ), a3( a3 ), a4( a4 )
        {
        }

    template<class TEventHandler>
    R operator()( TEventHandler d ) const
        {
        return d( a1, a2, a3, a4 );
        }
    };

template<typename R, typename A1, typename A2, typename A3, typename A4>
class TEvent4
    {
    typedef R return_type;
public:
    TEvent4()
        {

        }
    ~ TEvent4()
        {
        iDelegates.ResetAndDestroy();
        }

    TEvent4<R, A1, A2, A3, A4>& operator +=(
        TEventHandler4<R, A1, A2, A3, A4>& aDelegate )
        {
        iDelegates.Append( &aDelegate );
        return *this;
        }

    TEvent4<R, A1, A2, A3, A4>& operator -=(
        TEventHandler4<R, A1, A2, A3, A4>& aDelegate )
        {
        TInt pos = iDelegates.Find( &aDelegate );
        if ( pos != KErrNotFound )
            {
            iDelegates.Remove( pos );
            }
        return *this;
        }

    return_type operator()( A1 a1, A2 a2, A3 a3, A4 a4 ) const
        {
        for ( TInt i = 0; i < iDelegates.Count(); ++i )
            {
            ( *iDelegates[i] )( a1, a2, a3, a4 );
            }
        }
private:
    RPointerArray<TEventHandler4<R, A1, A2, A3, A4> > iDelegates;
    };

#define MAKEMETHODEVENTHANDLER0(returntype, class, method, object) \
    *TEventHandler0<returntype>::FromMethodL<class, &class::method>(object)

#define MAKEFUNCTIONEVENTHANDLER0(returntype, function) \
    *TEventHandler0<returntype>::FromFunctionL<&function>()

#define MAKEMETHODEVENTHANDLER1(returntype, type, class, method, object) \
    *TEventHandler1<returntype, type>::FromMethodL<class, &class::method>(object)

#define MAKEFUNCTIONEVENTHANDLER1(returntype, type, function) \
    *TEventHandler1<returntype, type>::FromFunctionL<&function>()


#endif // _EVENTS_H_
